package com.asiainfo.complier.editor;

import com.asiainfo.complier.common.ComplierInfo;
import com.asiainfo.complier.helper.UIHelper;

import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.undo.UndoManager;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.util.ArrayList;

public class LineEditor extends JEditorPane {
	/**
	 * LineEditor
	 */
	private static final long serialVersionUID = 7776766681500261952L;

	protected int _offsetX = 15;
	private Image img;
	protected boolean isShowNumber;
	private UndoManager undoManager;

	public void setShowLineNumber(boolean isShowLine) {
		isShowNumber = isShowLine;
		repaint();
	}

	/**
	 * append text
	 * 
	 * @param text
	 */
	public void appendText(String text) {
		int offset = getDocument().getLength() - 1;
		try {
			if (offset >= 0)
				getDocument().insertString(offset, text, null);
			else {
				setText(text);
			}
		} catch (BadLocationException e) {

			e.printStackTrace();
		}
	}

	protected int getOffsetX() {
		String s = "aabbcc" + getLineCount();

		Font font = new Font("dialoginput", Font.PLAIN, 12);
		FontRenderContext frc = new FontRenderContext(null, true, true);

		TextLayout tl = new TextLayout(s, font, frc);
		int w = (int) tl.getBounds().getWidth();
		if (w > _offsetX) {
			_offsetX = 15;
			this.setMargin(new Insets(0, _offsetX, 0, 0));
			repaint();
		}

		return _offsetX;

	}

	/**
	 * 
	 * @param text
	 */
	public void initText(String text) {
		setText(text);
		undoManager = new UndoManager();
		undoManager.setLimit(50000);
		getDocument().addUndoableEditListener(undoManager);
	}

	public LineEditor() {
		Font f = new Font("dialoginput", Font.PLAIN, 12);
		this.setFont(f);
		int offsetX = getOffsetX();
		this.setMargin(new Insets(0, offsetX, 0, 0));
		setDragEnabled(true);
		undoManager = new UndoManager();
		undoManager.setLimit(50000);

		img = UIHelper.getImage("com/asiainfo/images/dot.png");

		CodeEditorKit kit = new CodeEditorKit();
		setEditorKitForContentType("text/java", kit);
		setContentType("text/java");
		getDocument().addUndoableEditListener(undoManager);
		addMouseMotionListener(new MouseMotionListener() {

			public void mouseMoved(MouseEvent e) {
				int offsetX = getOffsetX();
				int x = e.getX();

				if (x < offsetX)
					setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
				else {

					setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
				}

			}

			public void mouseDragged(MouseEvent e) {

			}
		});

	}

	public boolean getShowLineNumber() {
		return isShowNumber;
	}

	/**
	 * get text line counts
	 * 
	 * @return
	 */
	public int getLineCount() {

		Rectangle rc;
		try {

			rc = modelToView(getDocument().getLength());
			if (rc != null) {
				return rc.y / rc.height + 1;
			} else {
				return 0;
			}
		} catch (BadLocationException e) {

			e.printStackTrace();
		}
		return 0;

	}

	public int getRowHeight() {
		try {
			Rectangle rc = modelToView(getDocument().getLength());
			if (rc != null)
				return rc.height;
			return 18;
		} catch (BadLocationException e1) {
			e1.printStackTrace();
		}
		return 0;
	}

	private int startLine, endLine = 0;

	public void setPaintLine(int startLine, int endLine) {
		this.startLine = startLine;
		this.endLine = endLine;
		repaint();

	}

	/**
	 * paint error message
	 * 
	 * @param g
	 * @param errorInfoList
	 */
	public void paintError(ArrayList<ComplierInfo> errorInfoList) {
		try {

			Graphics g = getGraphics();
			paint(g);
			int height = getRowHeight();
			Image errImage = UIHelper.getImage("com/asiainfo/images/error.png");

			for (ComplierInfo info : errorInfoList) {
				int y = height * info.getErrorLine() + 1;
				g.drawImage(errImage, 2,
						y - height / 2 - errImage.getHeight(null) / 2, null);
			}

		} catch (Exception e) {

		}
	}

	public void paint(Graphics g) {
		try {
			super.paint(g);
			if (isShowNumber) {

				int height = getRowHeight();

				g.setColor(new Color(0xD4, 0xD0, 0xC8));
				int offsetX = getOffsetX();
				g.drawLine(offsetX - 1, 0, offsetX - 1, this.getBounds().height);

				int y1 = (startLine) * height - height / 2;
				int y2 = (endLine) * height - height / 2;
				if (y2 > y1) {

					int tmp = y2;
					y2 = y1;
					y1 = tmp;
				}

				if (startLine != endLine) {
					g.setColor(new Color(0xD5, 0xD1, 0xCE));

					g.drawImage(img, 0, y1 - 4, null);
					g.drawImage(img, 0, y2 - 4, null);
					g.drawLine(img.getWidth(null) / 2, y1 - 4,
							img.getWidth(null) / 2, y2 + 4);
				}
			}
		} catch (Exception e) {

		}

	}

	/**
	 * get line offset dot
	 * 
	 * @param curDor
	 * @return
	 */
	public int getLineOfOffset(int curDor) {
		try {
			Rectangle rec = modelToView(curDor);

			if (rec != null)
				return rec.y / rec.height + 1;
			return 0;
		} catch (BadLocationException e) {

			e.printStackTrace();
		}
		return 0;
	}

	@Override
	public String getText() {
		try {

			return getDocument().getText(0, getDocument().getLength());
		} catch (BadLocationException e) {

			e.printStackTrace();
		}
		return "";

	}

	/**
	 * get offset of the document by line number
	 * 
	 * @param line
	 * @return
	 */
	public int getOffsetOfLine(int line) {
		int y = line * getRowHeight();
		Point pt = new Point(0, y);
		return viewToModel(pt) + 1;
	}

	/**
	 * go to line
	 * 
	 * @param line
	 */
	public void go2Line(int line) {
		int offset = getOffsetOfLine(line);

		setSelectionStart(offset);
		setSelectionEnd(offset);

	}

	public int getLineEndOfOffset(int pos) {
		try {
			Rectangle rec;
			rec = modelToView(pos);
			if (rec != null) {
				Point pt = new Point(0, rec.y);
				return viewToModel(pt) + 1;
			} else {
				return 0;
			}
		} catch (BadLocationException e) {

			e.printStackTrace();
		}
		return 0;

	}

	public UndoManager getUndoManager() {
		return undoManager;
	}

}
